package com.pengxh.app.gb28181.ui;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.provider.Settings;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;

import com.pengxh.androidx.lite.base.AndroidxBaseActivity;
import com.pengxh.androidx.lite.kit.StringKit;
import com.pengxh.app.gb28181.databinding.ActivityMainBinding;
import com.pengxh.app.gb28181.util.CameraDeviceHelper;
import com.pengxh.app.gb28181.util.G711Encoder;
import com.pengxh.app.gb28181.util.MediaPusher;
import com.pengxh.app.gb28181.util.SipConfig;
import com.pengxh.app.gb28181.util.SipEventCallback;
import com.pengxh.app.gb28181.util.YuvEncoder;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

public class MainActivity extends AndroidxBaseActivity<ActivityMainBinding> implements TextureView.SurfaceTextureListener, YuvEncoder.H264EncodeCallback {

    private static final String TAG = "MainActivity";
    private final Context mContext = this;
    private CameraManager mCameraManager;
    private CameraDevice mCameraDevice;
    private CameraCaptureSession mCaptureSession;
    private CaptureRequest.Builder mCaptureRequestBuilder;
    private ImageReader mImageReader;
    private Size mPreviewSize;
    private Handler mBackgroundHandler;
    private HandlerThread mBackgroundThread;
    private MediaPusher mMediaPusher;
    private AudioRecord mAudioRecord;
    private Thread mAudioRecordThread;

    private static final int SAMPLE_RATE = 8000;
    private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
    private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    private static final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;
    private boolean mIsRegistered;
    private YuvEncoder mYuvEncoder;
    private boolean mIsStreaming = false;

    private final AtomicLong mVideoFrameCount = new AtomicLong(0); // 视频帧计数器
    private final AtomicLong mAudioFrameCount = new AtomicLong(0); // 音频帧计数器

    private static final int AUDIO_FRAME_DURATION_MS = 20;
    private static final int PCM_BUFFER_SIZE = AUDIO_FRAME_DURATION_MS * SAMPLE_RATE / 1000 * 2;

    @Override
    protected void setupTopBarLayout() {

    }

    @Override
    protected void observeRequestState() {

    }

    @Override
    protected void initOnCreate(@Nullable Bundle bundle) {
        binding.textureView.setSurfaceTextureListener(this);
        mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        mMediaPusher = new MediaPusher();
    }

    @Override
    protected void onResume() {
        super.onResume();
        startBackgroundThread();
        // 先释放可能存在的旧资源
        releaseCamera();
        if (binding.textureView.isAvailable()) {
            openCamera();
        } else {
            binding.textureView.setSurfaceTextureListener(this);
        }
    }

    // 启动后台线程
    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("CameraBackground");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }

    @Override
    public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
        Log.d(TAG, "onSurfaceTextureAvailable: 相机画面已准备完毕");
        // 确保之前的相机资源已释放
        releaseCamera();
        openCamera();
    }

    @Override
    public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
        return false;
    }

    @Override
    public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

    }

    private void openCamera() {
        Log.d(TAG, "openCamera: 初始化相机");
        try {
            String[] cameraIds = mCameraManager.getCameraIdList();
            String cameraId = "";
            for (String id : cameraIds) {
                CameraCharacteristics cts = mCameraManager.getCameraCharacteristics(id);
                Integer facing = cts.get(CameraCharacteristics.LENS_FACING);
                if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) {
                    cameraId = id;
                    break;
                }
            }
            if (cameraId.isEmpty()) {
                Log.e(TAG, "无法找到前置摄像头");
                return;
            }

            // 获取相机特性
            CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
            StreamConfigurationMap configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            if (configMap == null) {
                Log.e(TAG, "无法获取相机配置");
                return;
            }

            Size[] sizes = configMap.getOutputSizes(SurfaceTexture.class);
            //找到很符合指定的标准比例且小于等于设备尺寸的尺寸。因为相机支持的尺寸可能大于设备尺寸
            mPreviewSize = CameraDeviceHelper.chooseOptimalSize(
                    sizes,
                    binding.textureView.getWidth(),
                    binding.textureView.getHeight(),
                    (double) 16 / 9);

            // 打开相机
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                mCameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
                    @Override
                    public void onOpened(@NonNull CameraDevice camera) {
                        mCameraDevice = camera;
                        createCameraPreviewSession();
                    }

                    @Override
                    public void onDisconnected(@NonNull CameraDevice camera) {
                        camera.close();
                        mCameraDevice = null;
                    }

                    @Override
                    public void onError(@NonNull CameraDevice camera, int error) {
                        camera.close();
                        mCameraDevice = null;
                        Log.e(TAG, "相机打开失败，错误码: " + error);
                    }
                }, mBackgroundHandler);
            } else {
                StringKit.show(this, "缺少相机权限");
            }
        } catch (CameraAccessException e) {
            Log.e(TAG, "openCamera: ", e);
        }
    }

    private void createCameraPreviewSession() {
        try {
            if (mBackgroundHandler == null) {
                startBackgroundThread();
            }
            // 创建预览Surface
            SurfaceTexture texture = binding.textureView.getSurfaceTexture();
            if (texture == null) {
                Log.e(TAG, "无法获取SurfaceTexture");
                return;
            }
            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            Surface previewSurface = new Surface(texture);

            // 创建捕获请求构建器并将预览Surface添加到构造器中，否则预览无画面
            mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mCaptureRequestBuilder.addTarget(previewSurface);

            // 仅预览画面
            mCameraDevice.createCaptureSession(Collections.singletonList(previewSurface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    if (mCameraDevice == null) return;
                    mCaptureSession = session;
                    // 自动对焦
                    mCaptureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
                    try {
                        // 开始预览
                        mCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(), null, mBackgroundHandler);
                    } catch (CameraAccessException e) {
                        Log.e(TAG, "配置预览失败", e);
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    Log.e(TAG, "创建相机预览会话失败");
                }
            }, mBackgroundHandler);
        } catch (CameraAccessException e) {
            Log.e(TAG, "createCameraPreviewSession: ", e);
        }
    }

    @Override
    protected void initEvent() {
        binding.registerButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startOrStopStream();
            }
        });
    }

    private void startEncoding() {
        mIsStreaming = true;
        mVideoFrameCount.set(0);
        mAudioFrameCount.set(0);

        if (mCaptureSession == null || mCameraDevice == null) return;
        try {
            // 创建 ImageReader
            mImageReader = ImageReader.newInstance(
                    mPreviewSize.getWidth(),
                    mPreviewSize.getHeight(),
                    ImageFormat.YUV_420_888,
                    2 // 小队列
            );
            mImageReader.setOnImageAvailableListener(mImageAvailableListener, mBackgroundHandler);

            // 重新配置 CaptureSession，加入 imageReaderSurface
            SurfaceTexture texture = binding.textureView.getSurfaceTexture();
            if (texture == null) {
                Log.e(TAG, "无法获取SurfaceTexture");
                return;
            }
            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            Surface previewSurface = new Surface(texture);
            Surface imageReaderSurface = mImageReader.getSurface();

            List<Surface> surfaces = Arrays.asList(previewSurface, imageReaderSurface);
            mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            for (Surface surface : surfaces) {
                mCaptureRequestBuilder.addTarget(surface);
            }

            mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    if (mCameraDevice == null) return;
                    mCaptureSession = session;
                    mCaptureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
                    try {
                        mCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(), null, mBackgroundHandler);
                    } catch (CameraAccessException e) {
                        Log.e(TAG, "Start encoding failed", e);
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    Log.e(TAG, "Encoding session failed");
                }
            }, mBackgroundHandler);

            // 初始化编码器
            if (mYuvEncoder == null) {
                mYuvEncoder = new YuvEncoder(mPreviewSize.getWidth(), mPreviewSize.getHeight(), this);
            }
            mYuvEncoder.prepare();

            // 启动音频
            startAudioRecording();

            mIsStreaming = true;
            Log.d(TAG, "Encoding started");
        } catch (Exception e) {
            Log.e(TAG, "startEncoding error", e);
            stopEncoding();
        }
    }

    private void stopEncoding() {
        mIsStreaming = false;

        try {
            // 停止音频
            if (mAudioRecord != null) {
                mAudioRecord.stop();
            }
            if (mAudioRecordThread != null) {
                try {
                    mAudioRecordThread.join();
                } catch (InterruptedException e) {
                    Log.e(TAG, "stopEncoding: ", e);
                }
            }

            // 释放编码器
            if (mYuvEncoder != null) {
                mYuvEncoder.release();
                mYuvEncoder = null;
            }

            // 关闭 ImageReader 并恢复纯预览
            if (mImageReader != null) {
                mImageReader.close();
                mImageReader = null;
            }

            // 重新创建只有预览的 session
            if (mCaptureSession != null) {
                mCaptureSession.close();
                mCaptureSession = null;
            }
            if (binding.textureView.isAvailable()) {
                createCameraPreviewSession(); // 回到纯预览
            }
            Log.d(TAG, "Encoding stopped");
        } catch (Exception e) {
            Log.e(TAG, "stopEncoding: ", e);
        }
    }

    private final ImageReader.OnImageAvailableListener mImageAvailableListener = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader imageReader) {
            if (!mIsStreaming) return; // 提前检查

            try (Image image = imageReader.acquireLatestImage()) {
                if (image == null || mYuvEncoder == null) return;

                // 转换为 90kHz PTS（精确计算）30fps → *3000；25fps → 90000/25=3600；20fps → *4500
//                long pts90kHz = mVideoFrameCount.getAndIncrement() * 3600;
                long nanoTime = System.nanoTime();
                long pts90kHz = (nanoTime * 90L) / 1_000_000L; // 精确转换为 90kHz 单位

                mYuvEncoder.encodeFrame(image, pts90kHz);
            } catch (Exception e) {
                Log.e(TAG, "Error processing image", e);
            }
        }
    };

    @Override
    public void onSpsPpsDecoded(byte[] sps, byte[] pps) {
        if (mMediaPusher != null) {
            mMediaPusher.notifySpsPps(sps, pps);
        }
    }

    @Override
    public void onYuvDataEncoded(byte[] h264, long timestamp90kHz, boolean isKeyFrame) {
        if (mMediaPusher != null) {
            mMediaPusher.pushVideoFrame(h264, timestamp90kHz, isKeyFrame);
        }
    }

    private void releaseCamera() {
        if (mYuvEncoder != null) {
            mYuvEncoder.release();
            mYuvEncoder = null;
        }

        if (mCaptureSession != null) {
            mCaptureSession.close();
            mCaptureSession = null;
        }

        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }

        if (mImageReader != null) {
            mImageReader.close();
            mImageReader = null;
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        releaseCamera();
        stopBackgroundThread();
    }

    // 停止后台线程
    private void stopBackgroundThread() {
        mBackgroundThread.quitSafely();
        try {
            mBackgroundThread.join();
            mBackgroundThread = null;
            mBackgroundHandler = null;
        } catch (InterruptedException e) {
            Log.e(TAG, "stopBackgroundThread: ", e);
        }
    }

    public void startOrStopStream() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (!mIsRegistered) {
                    startStream();
                } else {
                    stopStream();
                }
            }
        }).start();
    }

    //开始推流
    public void startStream() {
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
                NetworkInterface net = en.nextElement();
                for (Enumeration<InetAddress> enumIpAddr = net.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                    InetAddress inetAddress = enumIpAddr.nextElement();
                    if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
                        String localIp = inetAddress.getHostAddress();
                        String serialNumber = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
                        SipConfig config = new SipConfig(localIp,
                                "111.198.10.15", 22117,
                                "11010800002000000002", "1101080000",
                                "11010800001300021220", serialNumber,
                                "M1300021220", "1234qwer",
                                116.3975, 39.9085);
                        mMediaPusher.register(config, new SipEventCallback() {
                            @Override
                            public void onEventReceived(int code, String content) {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        StringKit.show(mContext, "响应码：" + code + "，内容：" + content);
                                        if (code == 200) {
                                            mIsRegistered = true;
                                            binding.registerButton.setText("注销流媒体");
                                        } else if (code == 201) {
                                            binding.registerButton.setText("流媒体注册");
                                            mIsRegistered = false;
                                        } else if (code == 1000) {
                                            startEncoding();
                                        } else if (code == 1001) {
                                            stopEncoding();
                                        }
                                    }
                                });
                            }
                        });
                        return;
                    }
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "startStream: ", e);
        }
    }

    private void startAudioRecording() {
        int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT);
        bufferSize = Math.max(bufferSize, PCM_BUFFER_SIZE); // 至少 320

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            Log.d(TAG, "startAudioRecording: 缺少录音权限");
            return;
        }

        mAudioRecord = new AudioRecord(AUDIO_SOURCE, SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, bufferSize);
        mAudioRecord.startRecording();

        mAudioRecordThread = new Thread(new Runnable() {
            @Override
            public void run() {
                android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
                byte[] pcm = new byte[PCM_BUFFER_SIZE]; // 320 bytes

                while (mIsStreaming && !Thread.currentThread().isInterrupted()) {
                    int readBytes = mAudioRecord.read(pcm, 0, pcm.length);
                    if (readBytes > 0 && mMediaPusher != null) {
                        byte[] alaw = G711Encoder.encode2alaw(pcm);

                        // 音频 PTS：每帧 20ms → 90k * 0.02 = 1800
//                        long audioPts90kHz = mAudioFrameCount.getAndIncrement() * 1800;
                        long nanoTime = System.nanoTime();
                        long audioPts90kHz = (nanoTime * 90L) / 1_000_000L;

                        mMediaPusher.pushAudioFrame(alaw, audioPts90kHz);
                    }
                }
            }
        });
        mAudioRecordThread.start();
    }

    //停止推流
    public void stopStream() {
        mMediaPusher.unregister();
    }
}